import greenfoot.*;
import java.util.List;
import java.util.ArrayList;

/**
 * En este se utiliza el scroll
 */
public class SWorld extends World
{
    private int scrollingWidth, scrollingHeight; // límites para el actor principal dentro de las coordenadas universales
    private int actorMinX, actorMaxX, actorMinY, actorMaxY; // límites para el actor principal dentro de las coordenadas del mundo
    private int AMT_X=0, AMT_Y=0; // cantidad inicial desplazado
    private int scrollType; // indica direcciones de desplazamiento (0 = ninguno, 1 = horizontal, 2 = vertical, 3 = ambos)
    Actor mainActor = null; // el actor que siempre permanece visible
    private List<Actor>genActors = new ArrayList(); //lista todos los objetos genéricos desplazamiento de actores
    private GreenfootImage background = null;
    Boolean start=false;
    private Boton jugar = new Boton("Play.png");//Boton Jugar
    private Boton ayuda = new Boton("Help.png");//Boton Ayuda
    private Boton creditos = new Boton("Credito.png");//Boton Creditos
    private Boton atras = new Boton("Atras.png");//Boton Atras
    /**
      * El constructor de una rueda de desplazamiento universal.
      * Crea un mundo sin límites y establece el tamaño del área desplazable.
      *
      * @ Param par en par la ventana de ancho
      * @ Param alto la altura de la ventana
      * @ Param cellsize el tamaño de cada celda
      * @ Param scrollWide el ancho desplazable (valor mínimo es de ancho de la ventana)
      * @ Param scrollHigh la altura de desplazamiento (valor mínimo es de altura de la ventana)
     */
    public SWorld(int wide, int high, int cellSize, int scrollWide, int scrollHigh)
    {
        super(cellSize==1?wide:(wide/2)*2+1, cellSize==1?high:(high/2)*2+1, cellSize, false);
        scrollType=(scrollWide>wide?1:0)+(scrollHigh>high?2:0);
        scrollingWidth=scrollType%2==1?scrollWide:wide;
        scrollingHeight=scrollType/2==1?scrollHigh:high;
        cargaMenu();
    }
    
    /**
    * El constructor de una horizontal (lateral) scroller.
      * Las llamadas al constructor scroller universal con scrollHigh igual al parámetro de altura de la ventana.
      *
      * @ Param par en par la ventana de ancho
      * @ Param alto la altura de la ventana
      * @ Param cellsize el tamaño de cada celda
      * @ Param scrollWide el ancho desplazable (valor mínimo es de ancho de la ventana)
     */
    public SWorld(int wide, int high, int cellSize, int scrollWide)
    {
        this(wide, high, cellSize, scrollWide,high);
       
    }
    
    /**
     * Agrega el actor principal en el mundo en el centro de la ventana. <br>
      * NOTA: Este método debe ser llamado antes de llamar a <i> setScrollingBackground </ i>.
      * Establece el rango de movimiento dentro de la ventana para el actor, y determina el rango horizontal de
      * Y el movimiento vertical desplazable permitido para el actor. <br>
      *
      * @ Param el actor principal que es estar siempre a la vista
      * @ Param xrange el rango de movimiento horizontal dentro de la ventana
      * @ Param YRange el rango vertical de circulación dentro de la ventana
     */
    public void setMainActor(Actor main, int xRange, int yRange)
    {
        if (main==null)
        {
            System.out.println("A main actor MUST be supplied.");
            System.out.println("");
            return;
        }
        super.addObject(main,10,10);
        //super.addObject(main, getWidth()/2, getHeight()/2);
        mainActor = main;
        xRange=(int)Math.min(xRange, getWidth());
        yRange=(int)Math.min(yRange, getHeight());
        actorMinX=getWidth()/3-xRange/2;
        //actorMinX=getWidth()/2-xRange/2;
        actorMaxX=getWidth()/2+xRange/2;
        //actorMaxX=getWidth()/2+xRange/2;
        actorMinY=getHeight()/2-yRange/2;
        actorMaxY=getHeight()/3;
        //actorMaxY=getHeight()/2+yRange/2;
    }
    
    /**
    * Añade un fondo de desplazamiento para el mundo, ver descripción del método para las notas sobre los resultados deseados <br>.
      * Nota: Para que este método funcione, el actor principal debe haber sido previamente establecido con <i> setMainActor </ i>. La imagen se
      * Se escala al tamaño apropiado y se centra en el mundo desplazable.
      *
      * @ Param scrollingBackground la imagen que se utiliza para el fondo de desplazamiento del mundo
     */
    public void setScrollingBackground(GreenfootImage scrollingBackground)    
    {
        if(mainActor==null)
        {
            System.out.println("'setMainActor' MUST be called prior to calling 'setScrollingBackground'.");
            System.out.println("");
            return;
        }
        background = new GreenfootImage(scrollingBackground);
        background.scale(scrollingWidth*getCellSize(), scrollingHeight*getCellSize());
        scrollBackground();
         setBackground("fondo.png");//fondo para el menu ///////////////////////////////////////////
    }
    
    /**
     *Rellena el fondo del área de desplazamiento con el fillImage <i> </ i>. <br>
      * Nota: Para que este método funcione, el actor principal debe haber sido previamente establecido con <i> setMainActor </ i>. La imagen se
      * Se utiliza para llenar el fondo de la zona de desplazamiento y está centrado en el mundo desplazable.
      *
      * @ Param fillImage la imagen para llenar el fondo del área con el desplazamiento 
     */
    public void fillScrollingBackground(GreenfootImage fillImage)
    {
        if(mainActor==null)
        {
            System.out.println("'setMainActor' MUST be called prior to calling 'fillScrollingBackground'.");
            System.out.println("");
            return;
        }
        if (fillImage.getWidth()<getWidth() && fillImage.getHeight()<getHeight())
        {
            setBackground(new GreenfootImage(fillImage));
            fillImage = getBackground();
        }
        background = new GreenfootImage(scrollingWidth*getCellSize(), scrollingHeight*getCellSize());
        for (int x=0; x<background.getWidth(); x+=fillImage.getWidth())
            for (int y=0; y<background.getHeight(); y+=fillImage.getHeight())
                background.drawImage(fillImage, x, y);
        scrollBackground();
    }
        
    /**
    * Agrega un objeto en el mundo, una lista en una matriz si el actor es un objeto desplazable
      *
      * @ Param obj el objeto de añadir al mundo
      * @ Param xLoc la coordenada x para colocar el objeto
      * @ Param yLoc la coordenada y para colocar el objeto
      * @ Param scroller una bandera que indica si este objeto es de tipo desplazable o no
     */
    public void addObject(Actor obj, int xLoc, int yLoc, boolean scroller)
    {
        super.addObject(obj, xLoc, yLoc);
        if(scroller) genActors.add(obj);
    }
    
    /**
      * Agrega un objeto desplazable en el mundo, enumerándolos en la matriz Actor.
      *
      * @ Param obj el objeto desplazable para añadir al mundo
      * @ Param xLoc la coordenada x para colocar el objeto
      * @ Param yLoc la coordenada y para colocar el objeto
     */
    public void addObject(Actor obj, int xLoc, int yLoc)
    {
        addObject(obj, xLoc, yLoc, true);
    }
    
    /**
     * Removes an object from the world, re-defining fields as neccessary
     *
     * @param obj the object to be removed from the world
     */
    public void removeObject(Actor obj)
    {
        if(obj==null)return;
        if(obj.equals(mainActor))mainActor=null;
        else genActors.remove(obj);
        super.removeObject(obj);
    }
    
    /**
     * Removes a collection of objects from the world, calling <i>removeObject(Actor)</i> for each one in the list
     *
     * @param objs the collection or list of objects to be removed from the world
     */
    public void removeObjects(List<Actor>objs)
    {
        for(Actor obj:objs)removeObject(obj);
    }
  
    /**
     * Runs the scrolling.
     */
    public void act()
    {
        if(start==true){
            scrollObjects();
            scrollBackground();
        }
        
        checaBotones();
    }
    public void checaBotones(){
        
        if(jugar.getPresionado()){
            
           jugar.setPresionado(false);
           remueveMenu();
           
           start=true;
        }
        else if(ayuda.getPresionado()){
            ayuda.setPresionado(false);
            remueveMenu();
            setBackground("Ayuda.png");
            addObject(atras,320,340);
        }
        else if(creditos.getPresionado()){
            creditos.setPresionado(false);
            remueveMenu();
            setBackground("fondo.png");
            addObject(atras,500,400);
        }
        else
        
        if(atras.getPresionado()){
            atras.setPresionado(false);
            cargaMenu();
            start=false;
        }
    }
    
    /**
     * se encarga de agregar los objetos del menu al escenario,para cargar la vista del menu.
     */
    public void cargaMenu(){
        setBackground("fondo.png");
        addObject(jugar,300,300);
        addObject(ayuda,100,300);
        addObject(creditos,500,300);
        removeObject(atras);
    }
    
    public void remueveMenu(){
        removeObject(jugar);
        removeObject(ayuda);
        removeObject(creditos);
       
    }
    
    /**
     * Scrolls the background image.
     */
    private void scrollBackground()
    {
        if (background==null ) return;
        GreenfootImage image = new GreenfootImage(background);
        image.drawImage(background, (getWidth()*getCellSize()-background.getWidth())/2-AMT_X*getCellSize(),
                                    (getHeight()*getCellSize()-background.getHeight())/2-AMT_Y*getCellSize());
        setBackground(image);
    }
    
    /**
     * Scrolls all scrollable object.  Determines how far outside boundary limits the main actor is, and moves all neccessary
     * objects in the same direction, moving the main actor back within boundary limits.  A background can be
     * made up of scrollable actor object(s) to produce a scrolling background; however, determining intersectors with object
     * will have to include the background object as being one or more of them when using <i>null</i> for the class of intersector.
     */
    private void scrollObjects()
    {
        if (mainActor==null) return;
        // determine how far the main actor is outside its standard window limits
        int dx=0, dy=0;
        if(mainActor.getX()<actorMinX) dx=actorMinX-mainActor.getX();
        if(mainActor.getX()>actorMaxX) dx=actorMaxX-mainActor.getX();
        if(mainActor.getY()<actorMinY) dy=actorMinY-mainActor.getY();
        if(mainActor.getY()>actorMaxY) dy=actorMaxY-mainActor.getY();
        if(dx==0 && dy==0) return; // not outside window limits
        // ** outside standard window limits **
        AMT_X-=dx; AMT_Y-=dy;// track scroll amount
        // move all objects to place main actor back within standard window limits
        mainActor.setLocation(mainActor.getX()+dx, mainActor.getY()+dy);
        for(Object obj : genActors)
        {
            Actor actor=(Actor)obj;
            actor.setLocation(actor.getX()+dx, actor.getY()+dy);
        }
        // determine how far the background is inside the world limits
        dx=0; dy=0;
        if(AMT_X > scrollingWidth/2-getWidth()/2) dx=AMT_X-(scrollingWidth/2-getWidth()/2);
        if(AMT_X < getWidth()/2-scrollingWidth/2) dx=AMT_X-(getWidth()/2-scrollingWidth/2);
        if(AMT_Y > scrollingHeight/2-getHeight()/2) dy=AMT_Y-(scrollingHeight/2-getHeight()/2);
        if(AMT_Y < getHeight()/2-scrollingHeight/2) dy=AMT_Y-(getHeight()/2-scrollingHeight/2);
        if(dx==0 && dy==0) return; // background image covers the world
        // ** background does not completely cover world limits
        AMT_X-=dx; AMT_Y-=dy; // adjust scroll amount
        // move all objects so background covers the world
        mainActor.setLocation(mainActor.getX()+dx, mainActor.getY()+dy);
        for(Object obj : genActors)
        {
            Actor actor=(Actor)obj;
            actor.setLocation(actor.getX()+dx, actor.getY()+dy);
        }
        // determine how far main actor is outside universal limits
        dx=0; dy=0;
        if(mainActor.getX() < 0) dx=0-mainActor.getX();
        if(mainActor.getX() > getWidth()-1) dx=(getWidth()-1)-mainActor.getX();
        if(mainActor.getY() < 0) dy=0-mainActor.getY();
        if(mainActor.getY() > getHeight()-1) dy=(getHeight()-1)-mainActor.getY();
        if(dx==0 && dy==0) return;
        // ** outside universal limits
        // move main actor back within world limits
        mainActor.setLocation(mainActor.getX()+dx, mainActor.getY()+dy);
    }
}
